<!-- 本组件纯木偶组件，不要将业务逻辑写入此组件 -->

<script lang="ts">
  import { onMount, tick, createEventDispatcher, onDestroy } from 'svelte';
  import type { Ability } from '@vtuber/ThreeSDK';
  import useCaption from '../hooks/useCaption';
  import useEngine from '../hooks/useEngine';
  import usePlay from '../hooks/usePlay';
  import {
    errorReport,
    isGPUAccelerated,
    isSupportVersion,
    StutterDetector,
    getUserId
  } from '../utils/tools';
  import config from '../config/index';
  const emit = createEventDispatcher();
  // 初始化引擎hooks
  let {
    initResult,
    sdkInitData,
    canvasRef,
    vtuberIndex,
    engine,
    humanInfo,
    initEngine,
    setVtuber,
    changeHumanInfo
  } = useEngine();

  export { sdkInitData, vtuberIndex, humanInfo };

  // 播放hooks
  let { value, playInit, wsHook, isWsHook, adjustVolume } = usePlay();
  const play = () => {
    if (!isWsHook(wsHook)) {
      return;
    }
    wsHook.play(
      false,
      (data) => {
        // 每句播放的时候，将上一次的播放语句，存放到已播放属性中
        captionData.removedValue += captionData.nowValue;
        captionData.nowValue = data.text;
        captionData.remainValue = captionData.remainValue.replace(captionData.nowValue, '');
        if (captionData.nowValue && caption.autoPosition) {
          tick().then(() => {
            highLightPosition(captionRef);
          });
        }
        emit('updateCaptionData', { captionData });
      },
      // @ts-ignore -此处是库的问题，这里有返回boolean值
      (isFinish: boolean) => {
        emit('updateFinish', { isFinish });
        if (isFinish) {
          captionData.nowValue = '';
        }
      }
    );
  };
  const stop = (stopAll: boolean = false) => {
    if (!isWsHook(wsHook)) {
      return;
    }
    wsHook.stop(stopAll);
  };
  const setVolume = (volume: number) => {
    adjustVolume(volume, engine);
  };
  export { value, play, stop, setVolume };
  $: {
    if (value) {
      playInit(value, engine, sdkInitData)
        .then((wsHookParams) => {
          wsHook = wsHookParams;
          play();
        })
        .catch((error) => {
          errorReport({
            name: `播放初始化失败 ${error.name}`,
            stack: error.stack,
            message: error.message
          });
        });
      captionData.remainValue = value;
      captionData.nowValue = '';
      captionData.removedValue = '';
    }
  }

  // 字幕hooks
  let { caption, highLightPosition, initCaption, captionData, originCaptionData } = useCaption();
  export { caption, originCaptionData };
  // 字幕dom
  let captionRef: HTMLElement | void;

  // 业务方传默认字幕
  $: {
    const { removedValue, remainValue } = originCaptionData;
    removedValue && (captionData.removedValue = removedValue);
    remainValue && (captionData.remainValue = remainValue);
    captionData.nowValue = '';
  }

  // 是否需要使用兜底模式
  let needTolerent: boolean = false;
  // 兼容性视频播放video标签
  let videoRef: HTMLVideoElement | null = null;
  export let isPlaying: boolean = false;
  // 判断是否需要暂停的timer
  let videoTimer = null;
  $: {
    if (videoRef && needTolerent) {
      if (isPlaying) {
        videoTimer && clearTimeout(videoTimer);
        videoRef.play();
      } else {
        // 设置延迟一秒，如果一秒内有继续播放，则判断为还在一条内容当中，无需暂停
        videoTimer = setTimeout(() => {
          videoRef && videoRef.pause();
          videoRef && (videoRef.currentTime = 0);
        }, 1000);
      }
    }
  }
  let checkFrameRateTimer = null;
  const checkRate = async () => {
    const isSupportVersionResult = await isSupportVersion();
    const isGPUAcceleratedResult = isGPUAccelerated();
    checkFrameRateTimer && clearInterval(checkFrameRateTimer);
    let text = '';
    if (!isSupportVersionResult || !isGPUAcceleratedResult) {
      errorReport({
        name: '虚拟人点击初始化异常',
        message: `${isSupportVersionResult ? '' : '版本过低'}；${isGPUAcceleratedResult ? '' : 'GPU加速异常'}`,
        stack: ''
      });
      const { notGpuTipsKey, notVersionTipsKey } = config.localstorageKeys;
      let localstorageKey = '';
      [text, localstorageKey] = !isSupportVersionResult
        ? ['已采用兼容性播放，获得更好的体验，请到官网下载使用最新版本客户端', notVersionTipsKey]
        : ['检测到GPU异常，已自动切换至兼容性播报', notGpuTipsKey];
      const userid = await getUserId();
      // 如果已经提示过，则不再提示
      if (window.localStorage.getItem(`${localstorageKey}${userid}`)) {
        text = '';
      } else {
        window.localStorage.setItem(`${localstorageKey}${userid}`, '1');
      }
      needTolerent = true;
      engine.imgRender = false;
    } else {
      needTolerent = false;
      const stutterDetector = new StutterDetector();
      checkFrameRateTimer = setInterval(() => {
        // @ts-ignore
        console.log('帧率', engine?.fps);
        // @ts-ignore
        const isHighFrameRate = stutterDetector.checkFrameRate((engine?.fps as number) || 0);
        // @ts-ignore
        const noFluctuation = stutterDetector.checkFluctuation((engine?.fps as number) || 0);
        const isGPUAcceleratedResult = isGPUAccelerated();
        if (!isHighFrameRate || !noFluctuation || !isGPUAcceleratedResult) {
          errorReport({
            name: '虚拟人10s定时检查帧率异常',
            message: `${isHighFrameRate ? '' : '帧率30s内连续低于24帧，或者低于10帧次数大于5次'}；${noFluctuation ? '' : '帧率1分钟内波动超过20次数大于5次'}；${isGPUAcceleratedResult ? '' : 'GPU加速异常'}`,
            stack: ''
          });
          console.log('异常，已开启兼容性');
          needTolerent = true;
          engine.imgRender = false;
          checkFrameRateTimer && clearInterval(checkFrameRateTimer);
          const textTemp =
            !isHighFrameRate || !noFluctuation
              ? '检测到卡顿，已自动切换至兼容性播报'
              : '检测到GPU异常，已自动切换至兼容性播报';
          emit('updateNeedTolerent', {
            needTolerent,
            textStr: textTemp,
            isLag: !isHighFrameRate || !noFluctuation
          });
        }
      }, 10 * 1000);
    }
    emit('updateNeedTolerent', { needTolerent, textStr: text });
  };
  onMount(() => {
    tick()
      .then(() => initEngine(canvasRef, sdkInitData))
      .then((engineRes) => {
        if (engineRes) {
          engine = engineRes;
        }
      })
      .then(() =>
        Promise.all([setVtuber(vtuberIndex, engine as Ability), initCaption(engine as Ability)])
      )
      .then(() => changeHumanInfo(humanInfo, engine as Ability))
      .then(() => {
        initResult = true;
        emit('updateInitResult', { initResult: true });
      })
      .catch((error: Error) => {
        errorReport({
          name: `虚拟人初始化的时候错误 ${error?.name}`,
          message: error?.message,
          stack: error?.stack
        });
        emit('updateInitResult', { initResult: false });
      })
      .finally(() => {
        checkRate();
      });
  });
  onDestroy(() => {
    checkFrameRateTimer && clearInterval(checkFrameRateTimer);
  });
  export const quitWsEngine = () => {
    if (engine) {
      engine.closeWS();
      engine.quit();
    }
  };
</script>

{#if caption.show && value}
  <div class="caption {caption.className || ''}" bind:this={captionRef}>
    {captionData.removedValue}<span class="high-light">{captionData.nowValue}</span
    >{captionData.remainValue}
  </div>
{/if}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
  class="human-container"
  on:click={() => {
    emit('clickVtuber');
  }}
>
  <div class="human-ins-container">
    {#if needTolerent}
      <!-- svelte-ignore a11y-media-has-caption -->
      <video
        src="//s.thsi.cn/cd/b2cweb-fe-common-resource-pod/js/vtuber/2.0.0/tolerent.mp4"
        loop
        muted
        class="tolerent-video"
        bind:this={videoRef}
      ></video>
    {:else}
      <canvas class="{humanInfo.humanClassName || ''} human-ins" bind:this={canvasRef} />
    {/if}
  </div>
  {#if initResult}
    <img
      src="//i.thsi.cn/staticS3/mobileweb-upload-static-server.img/m/atom/0b9a9f05-2544-435c-adcb-acde7587b46a.png"
      alt=""
      class="light {humanInfo.lightClass || ''}"
    />
    <img
      src="//i.thsi.cn/staticS3/mobileweb-upload-static-server.img/m/atom/39f8b03c-6e5c-47ed-808c-8c0bf5bf8eb0.png"
      alt=""
      class="stage {humanInfo.stageClass || ''}"
    />
  {/if}
</div>

<style lang="less">
  .caption {
    padding: 12px;
    overflow-y: auto;
    .high-light {
      color: red;
    }
  }
  @keyframes widthVariation {
    0% {
      width: 177px;
    }
    50% {
      width: 150px;
    }
    100% {
      width: 177px;
    }
  }
  @keyframes opacityVariation {
    0% {
      opacity: 1;
    }
    50% {
      opacity: 0.8;
    }
    100% {
      opacity: 1;
    }
  }
  .human-container {
    position: relative;
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 91px;
    height: 375px;
    .human-ins-container {
      width: 250px;
      height: 375px;
      z-index: 2;
      mix-blend-mode: screen;
      pointer-events: none;

      .tolerent-video {
        mix-blend-mode: screen;
        width: 100%;
        height: 114%;
        margin-top: -12%;
      }
      .human-ins {
        width: 100%;
        height: 100%;
      }
    }
    .light {
      width: 170px;
      height: 220px;
      z-index: 3;
      margin-top: -220px;
      animation:
        widthVariation 3s infinite,
        opacityVariation 4s infinite;
    }
    .stage {
      position: absolute;
      bottom: -25px;
      width: 115px;
      height: 31px;
      z-index: 1;
    }
  }
</style>
